/*****************************************************************************/
/**
 *  @file   Write.cpp
 *  @author Naohisa Sakamoto
 */
/*----------------------------------------------------------------------------
 *
 *  Copyright (c) Visualization Laboratory, Kyoto University.
 *  All rights reserved.
 *  See http://www.viz.media.kyoto-u.ac.jp/kvs/copyright/ for details.
 *
 *  $Id$
 */
/*****************************************************************************/
#include "Write.h"
#include <sstream>


namespace
{

template <typename T>
kvs::AnyValueArray DividedArray( const kvs::AVSField& fld, const size_t ndivs, const size_t index )
{
    const size_t veclen = fld.veclen();
    const kvs::Vector3ui resolution = fld.dim();
    const kvs::ValueArray<T> values = fld.values().asValueArray<T>();
    const size_t dimx = resolution.x() / ndivs;
    const size_t dimy = resolution.y();
    const size_t dimz = resolution.z();

    kvs::ValueArray<T> div_values( dimx * dimy * dimy * veclen );
    for ( size_t k = 0, K = 0; k < dimz; k++, K++ )
    {
        for ( size_t j = 0, J = 0; j < dimy; j++, J++ )
        {
            for ( size_t i = 0, I = dimx * index; i < dimx; i++, I++ )
            {
                const size_t div_values_index = k * dimx * dimy + j * dimx + i;
                const size_t values_index = K * resolution.x() * resolution.y() + J * resolution.x() + I;
                for ( size_t v = 0; v < veclen; v++ )
                {
                    div_values[ veclen * div_values_index + v ] = values[ veclen * values_index + v ];
                }
            }
        }
    }

    return div_values;
}

std::string Number( const size_t number )
{
    std::ostringstream oss;
    oss.setf( std::ios::right );
    oss.fill( '0' );
    oss.width( 5 );
    oss << number;
    return oss.str();
}

}

namespace kvsbloodvis
{

namespace util
{

bool Write( kvs::AVSField& fld, std::string filename, bool verbose, kvs::Indent indent )
{
    bool retval = true;
    if ( !fld.write( filename ) ) retval = false;
    if ( verbose ) fld.print( std::cout, indent );
    return retval;
}

bool Write( kvs::AVSField& fld, std::string filename, size_t ndivs, bool verbose, kvs::Indent indent )
{
    bool retval = true;
    const kvs::Vector3ui resolution = kvs::Vector3ui( fld.dim().x() / ndivs, fld.dim().y(), fld.dim().z() );
    const kvs::AnyValueArray values = fld.values();
    for ( size_t index = 0; index < ndivs; index++ )
    {
        kvs::AnyValueArray div_values;
        if ( fld.dataType() == kvs::AVSField::Byte )
        {
            div_values = ::DividedArray<kvs::UInt8>( fld, ndivs, index );
        }
        else if ( fld.dataType() == kvs::AVSField::Float )
        {
            div_values = ::DividedArray<kvs::Real32>( fld, ndivs, index );
        }

        std::string number = ::Number( index );

        kvs::AVSField div_avs;
        div_avs.setBits( fld.bits() );
        div_avs.setSigned( fld.isSigned() );
        div_avs.setVeclen( fld.veclen() );
        div_avs.setNSpace( fld.nspace() );
        div_avs.setNDim( fld.ndim() );
        div_avs.setDim( resolution );
        div_avs.setFieldType( fld.fieldType() );
        div_avs.setDataType( fld.dataType() );
        div_avs.setValues( div_values );
        if ( !div_avs.write( filename + "_" + number + ".fld" ) ) retval = false;
        if ( verbose ) div_avs.print( std::cout, indent );
    }

    return retval;
}

} // end of namespace util

} // end of namespace kvsbloodvis
